Introduction
The explanations are mostly adapted from Investopedia. On the technical side, there are five statistical risk measurements used in modern portfolio theory (MPT);
- alpha
- beta
- R-squared
- standard deviation
- Sharpe ratio.
Among which the Standard Deviation and SharpeRatio will be calculated in the following sections.
MPT suggested that it is possible to construct an “efficient frontier” of an optimal portfolio, whereby it is possible to calculate the maximum possible expected return for a given level of risk, this is done through diversification.
Through R packages such as quantmod, PortfolioAnalytics, and PerformanceAnalytics, Stocks, Bounds and index data can be pulled from the internet. Then, it can be analyzed and used to construct a custom portfolio that is tailored to specific cost and objectives. Portfolio such as Efficient Frontier, which measures expected return versus Risk can then be constructed.
Packages used
require(PortfolioAnalytics)
Loading required package: PortfolioAnalytics
package <U+393C><U+3E31>PortfolioAnalytics<U+393C><U+3E32> was built under R version 3.3.3Loading required package: zoo
package <U+393C><U+3E31>zoo<U+393C><U+3E32> was built under R version 3.3.3
Attaching package: <U+393C><U+3E31>zoo<U+393C><U+3E32>
The following objects are masked from <U+393C><U+3E31>package:base<U+393C><U+3E32>:
as.Date, as.Date.numeric
Loading required package: xts
package <U+393C><U+3E31>xts<U+393C><U+3E32> was built under R version 3.3.3Loading required package: foreach
package <U+393C><U+3E31>foreach<U+393C><U+3E32> was built under R version 3.3.3foreach: simple, scalable parallel programming from Revolution Analytics
Use Revolution R for scalability, fault tolerance and more.
http://www.revolutionanalytics.com
Loading required package: PerformanceAnalytics
package <U+393C><U+3E31>PerformanceAnalytics<U+393C><U+3E32> was built under R version 3.3.3
Package PerformanceAnalytics (1.4.3541) loaded.
Copyright (c) 2004-2014 Peter Carl and Brian G. Peterson, GPL-2 | GPL-3
http://r-forge.r-project.org/projects/returnanalytics/
Attaching package: <U+393C><U+3E31>PerformanceAnalytics<U+393C><U+3E32>
The following object is masked from <U+393C><U+3E31>package:graphics<U+393C><U+3E32>:
legend
require(PerformanceAnalytics)
require(quantmod)
Loading required package: quantmod
package <U+393C><U+3E31>quantmod<U+393C><U+3E32> was built under R version 3.3.3Loading required package: TTR
package <U+393C><U+3E31>TTR<U+393C><U+3E32> was built under R version 3.3.3Version 0.4-0 included new data defaults. See ?getSymbols.
Learn from a quantmod author: https://www.datacamp.com/courses/importing-and-managing-financial-data-in-r
require(zoo)
require(plotly)
Loading required package: plotly
package <U+393C><U+3E31>plotly<U+393C><U+3E32> was built under R version 3.3.3Loading required package: ggplot2
package <U+393C><U+3E31>ggplot2<U+393C><U+3E32> was built under R version 3.3.3
Attaching package: <U+393C><U+3E31>plotly<U+393C><U+3E32>
The following object is masked from <U+393C><U+3E31>package:ggplot2<U+393C><U+3E32>:
last_plot
The following object is masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:
filter
The following object is masked from <U+393C><U+3E31>package:graphics<U+393C><U+3E32>:
layout
require(data.table)
Loading required package: data.table
package <U+393C><U+3E31>data.table<U+393C><U+3E32> was built under R version 3.3.3data.table 1.10.4.3
The fastest way to learn (by data.table authors): https://www.datacamp.com/courses/data-analysis-the-data-table-way
Documentation: ?data.table, example(data.table) and browseVignettes("data.table")
Release notes, videos and slides: http://r-datatable.com
Attaching package: <U+393C><U+3E31>data.table<U+393C><U+3E32>
The following objects are masked from <U+393C><U+3E31>package:xts<U+393C><U+3E32>:
first, last
## for optimisation
# library(DEoptim)
# library(ROI)
# require(ROI.plugin.quadprog)
# require(ROI.plugin.glpk)
Data Input
Selecting the 5 biggest technology stocks and GSPC(S&P500), HSI(HK index) and STI(SG Index) as inputs.
# Get financial data(adjusted returns are what we are after) with quantmod with yahoo
# Alternatively, quantmod appears to play well with quanda and google as well
# for the 5 horsemen of the techpocalyse + S&P index
getSymbols(c("MSFT", "GOOGL", "AAPL", "AMZN", "FB", "^GSPC", "^HSI", "^STI"), src="yahoo", auto.assign=TRUE)
[1] "MSFT" "GOOGL" "AAPL" "AMZN" "FB" "GSPC" "HSI" "STI"
# from="2007-01-01" # by default
# Assign to dataframe
# for data from yahoo the adjusted close price is at the 6th column
prices.data <- merge.zoo(MSFT[,6], GOOGL[,6], AAPL[,6], AMZN[,6], FB[,6], GSPC[,6], HSI[,6], STI[,6])
# note that for the current version of quantmod, the adjusted close column appears to no longer include dividend adjustments
# Calculate returns
returns.data <- CalculateReturns(prices.data) # this use the basic lag function, which will run into issue with tidy verse
# note there is two commonly two ways to calculate returns, one is arithmetic and the other is logarithmic
# by default, CalculateReturns() function use arithmetic
returns.data <- na.omit(returns.data)
# Set names
colnames(returns.data) <- c("MSFT", "GOOGL", "AAPL", "AMZN", "FB", "^GSPC", "^HSI", "^STI")
Return and Risk explanation
two common methods to calculate return
\(r_t = \frac{P_t-P_{t-1}}{P_{t-1}} = \frac{P_t}{P_{t-1}}-1\)
\(r_t = \log{\frac{P_t}{P_{t-1}}} = \log{P}- \log{P_{t-1}}\)
While there are various methods to characterize risk, the most popular parameter is the Standard deviation, that which will be explored in the following sections, it is important to note that risk can be measured in other methods too. Such as
From Investopedia
- Standard Deviation(StdDev)
The most common risk measure used in both hedge fund and mutual fund evaluations is the standard deviation. The standard deviation, in this case, is the level of volatility of returns measured in percentage terms, and usually provided on an annual basis. Standard deviation gives a good indication of the variability of annual returns and makes it easy to compare to other funds when combined with annual return data
VaR measures the dollar-loss expectation that can occur with a 5% probability. It adds another dimension because it makes it possible to compare two funds with different average returns and standard deviation. VaR would indicate the dollar amount of loss that is possible with each fund with a 5% probability.
Put another way, VaR would tell you with 95% confidence that your losses would not exceed a certain point. (You can never be 100% confident that you won’t lose an entire investment.) It tries to answer the question “Given an investment of a particular return and volatility, what’s the worst that could happen?”
Expected Shortfall (ES) is a risk measure-a concept used in the field of financial risk measurement to evaluate the market risk or credit risk of a portfolio. The “expected shortfall at q% level” is the expected return on the portfolio in the worst {q} q% of cases. ES is an alternative to value at risk that is more sensitive to the shape of the tail of the loss distribution. Expected shortfall is also called conditional value at risk (CVaR), average value at risk (AVaR), and expected tail loss (ETL).
Defining some portfolio parameters
A single item is thus restricted take a between 0.05 to 0.45 portion of the portfolio. The portfolio is specified to be a full investment.
# initial portfolio object
init <- portfolio.spec(assets=colnames(returns.data))
# initial constraints
init <- add.constraint(portfolio=init, type="full_investment")
# init <- add.constraint(portfolio=init, type="long_only")
init <- add.constraint(portfolio=init, type="box", min=0.05, max=0.45)
# init <- add.constraint(portfolio=init, type="group",
# groups=list(c(1, 3),
# c(2, 4, 5)),
# group_min=0.05,
# group_max=0.7)
Optimization and Calculation
Optimize the portfolio using random
## A more Conventional approach is treating risk as StdDev
## Creates a new portfolio object using portf and adds StdDev as an objective
meanstd.portf <- add.objective(portfolio=init, type="risk", name="StdDev") %>%
add.objective(portfolio=., type="return", name="mean")
opt <- optimize.portfolio(returns.data, meanstd.portf, optimize_method="random", trace=T, search_size = 20000)
Leverage constraint min_sum and max_sum are restrictive,
consider relaxing. e.g. 'full_investment' constraint should be min_sum=0.99 and max_sum=1.01
executing %dopar% sequentially: no parallel backend registered
chart.RiskReward(opt, risk.col="StdDev", return.col="mean", chart.assets = F)

meanvar.ef<- create.EfficientFrontier(R=returns.data, portfolio=meanstd.portf, type="mean-var", n.portfolios = 50)
# summary(meanStd, digits=2)
# The RAR.text argument can be used for the risk-adjusted-return name on the legend,
# by default it is 'Modified Sharpe Ratio'
chart.EfficientFrontier(meanvar.ef, match.col="StdDev", type="l", RAR.text="Sharpe Ratio", pch=4, rf = 0.01/12)

Sharpe Ratio
“The Sharpe ratio characterizes how well the return of an asset compensates the investor for the risk taken”. The higher Sharpe Ratio means the better investment option. In a set of risky assets, we can find the optimal portfolio asset allocations so that the Sharpe Ration is the largest.
In another word, The Sharpe ratio is simply the return per unit of risk (represented by variability).
The capital market line (CML) appears in the capital asset pricing model to depict the rates of return for efficient portfolios subject to the risk level (standard deviation) for a market portfolio and the risk-free rate of return.
The capital market line is created by sketching a tangent line from the intercept point on the efficient frontier to the place where the expected return on a holding equals the risk-free rate of return. However, the CML is better than the efficient frontier because it considers the infusion of a risk-free asset in the market portfolio.
# extracting resutls from the class "frontier", extractStats() doesn't work for frontier class
meanvar.ef.allocation<-as.data.frame(summary(meanvar.ef)[[1]])
meanvar.ef.output<-as.data.frame(summary(meanvar.ef)[[2]])
# setting the row name as id for the output
meanvar.ef.output$id <-as.integer(row.names(meanvar.ef.output))
meanvar.ef.allocation$id <-as.integer(row.names(meanvar.ef.allocation))
#calculate the ShapeRatio for the EF outuput
setDT(meanvar.ef.output)[, SharpeRatio:= mean / StdDev]
## contructing CML line
MaxSharpe<-meanvar.ef.output[SharpeRatio==max(SharpeRatio)]
risk_free_rate= 0.01/12 # bound/ FD
ratio<-seq(0,1,0.1)
CML<- data.table(
CML_return=MaxSharpe$mean*ratio + risk_free_rate*(1-ratio),
CML_risk = MaxSharpe$StdDev*ratio
)
Plotting the results with plotly
Note that the mean returns and standard deviation depicted here are monthly figures
this plot setup is inspired by https://moderndata.plot.ly/portfolio-optimization-using-r-and-plotly/.
ex <- data.frame(extractStats(opt))
# data.frame(extractStats(meanvar.ef))
plot_ly(data =meanvar.ef.output, x = ~StdDev, y = ~mean, color = ~SharpeRatio, mode = "markers", showlegend = F,
type = "scatter", inherit = F) %>%
add_trace(data = ex, x = ~StdDev, y = ~mean, mode = "markers", showlegend = F, marker = list(color = "#F7C873", size = 5),
type = "scatter") %>%
add_lines(data = CML, x= ~CML_risk, y = ~CML_return)%>%
layout(title = "Random Portfolios with Plotly",
yaxis = list(title = "Mean Returns", tickformat = ".2%"),
xaxis = list(title = "Standard Deviation", tickformat = ".2%"),
paper_bgcolor = 'rgb(248, 248, 255)',
plot_bgcolor = 'rgb(248, 248, 255)',
legend = list(x = 0.029, y = 1.038,
font = list(size = 10)))
The inherit argument has been deprecated.package <U+393C><U+3E31>bindrcpp<U+393C><U+3E32> was built under R version 3.3.3
Allocation of investment among the Efficient Frontier
The portfolio across the Efficient Frontier can be visuallised as follow, along with the Sharpe Ratio of that particular setup for portfolio.
meanvar.ef.allocation.melt <- reshape2::melt(meanvar.ef.allocation, id.vars=c("id"))
plot_ly(meanvar.ef.allocation.melt, x = ~id, y = ~value, color = ~variable, type = "bar") %>%
add_trace(data = meanvar.ef.output, x = ~id, y = ~SharpeRatio, type = 'scatter', mode = 'lines', name = 'SharpeRatio',
yaxis = 'y2',
line = list(color = '#45171D'),
hoverinfo = "text",
text = ~paste(SharpeRatio), inherit = F) %>%
layout(title = "Portfolio weights across frontier", barmode = "stack",
xaxis = list(title = "Index"),
yaxis = list(title = "Weights(%)", tickformat = ".0%"),
yaxis2 = list(side = 'right', overlaying = "y", title = 'SharpeRatio', showgrid = FALSE, zeroline = FALSE),
legend = list(x = 0.029, y = 1.038,
font = list(size = 10)),
margin = list(l = 100, r = 50, t = 70, b = 70),
paper_bgcolor = 'rgb(248, 248, 255)',
plot_bgcolor = 'rgb(248, 248, 255)')
Custom cost and return for portfolio optimization
Below show the optimization of the portfolio using a custom function, in this case, the annual mean and std. this is adapted and slightly modified from https://stat.ethz.ch/pipermail/r-sig-finance/2016q1/013817.html
# Define mean PA function
Annualmean <- function(R, weights, n=60, geometric=FALSE){
as.vector(sum(Return.annualized(xts::last(R,n), geometric=geometric)*weights))
}
# Define std annually function
Annualsd <- function(R, weights=NULL){
as.numeric(StdDev(R=R, weights=weights)*sqrt(12)) # hardcoded for monthly data
}
#annualized return
meanstd.portf <- add.objective(portfolio=meanstd.portf,
type="return", # the kind of objective this is
name="Annualmean", # name of the function
multiplier=1 # use it in the objective
)
#annualized standard deviation
meanstd.portf <- add.objective(portfolio=meanstd.portf,
type="risk", # the kind of objective this is
name="Annualsd", # to minimize from the sample
multiplier=1 # use it in the objective
)
# make sure to run with trace=TRUE for the extract stats output
opt <- optimize.portfolio(returns.data, meanstd.portf, optimize_method="random", trace=TRUE)
Leverage constraint min_sum and max_sum are restrictive,
consider relaxing. e.g. 'full_investment' constraint should be min_sum=0.99 and max_sum=1.01
chart.RiskReward(opt, risk.col="Annualsd.Annualsd", return.col="Annualmean.Annualmean")

LS0tDQp0aXRsZTogIk1QVCAmIEVmZmljaWVudCBGcm9udGllciINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZl9wcmludDogdGliYmxlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDINCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6ICcyJw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQotLS0NCg0KI1tNb2Rlcm4gUG9ydGZvbGlvIFRoZW9yeSAoTVBUKV0oaHR0cHM6Ly93d3cuaW52ZXN0b3BlZGlhLmNvbS93YWxrdGhyb3VnaC9mdW5kLWd1aWRlL2ludHJvZHVjdGlvbi8xL21vZGVybi1wb3J0Zm9saW8tdGhlb3J5LW1wdC5hc3B4I2l4eno1ME1mM0hIaXggKQ0KDQojIEludHJvZHVjdGlvbg0KVGhlIGV4cGxhbmF0aW9ucyBhcmUgbW9zdGx5IGFkYXB0ZWQgZnJvbSBJbnZlc3RvcGVkaWEuIE9uIHRoZSB0ZWNobmljYWwgc2lkZSwgdGhlcmUgYXJlIGZpdmUgc3RhdGlzdGljYWwgcmlzayBtZWFzdXJlbWVudHMgdXNlZCBpbiBtb2Rlcm4gcG9ydGZvbGlvIHRoZW9yeSAoTVBUKTsgDQoNCjEuICphbHBoYSoNCjIuICpiZXRhKg0KMy4gKlItc3F1YXJlZCogDQo0LiAqc3RhbmRhcmQgZGV2aWF0aW9uKg0KNS4gKlNoYXJwZSByYXRpbyouIA0KDQpBbW9uZyB3aGljaCB0aGUgKlN0YW5kYXJkIERldmlhdGlvbiAqYW5kICpTaGFycGVSYXRpbyogd2lsbCBiZSBjYWxjdWxhdGVkIGluIHRoZSBmb2xsb3dpbmcgc2VjdGlvbnMuDQoNCk1QVCBzdWdnZXN0ZWQgdGhhdCBpdCBpcyBwb3NzaWJsZSB0byBjb25zdHJ1Y3QgYW4gImVmZmljaWVudCBmcm9udGllciIgb2YgYW4gb3B0aW1hbCBwb3J0Zm9saW8sIHdoZXJlYnkgaXQgaXMgcG9zc2libGUgdG8gY2FsY3VsYXRlIHRoZSBtYXhpbXVtIHBvc3NpYmxlIGV4cGVjdGVkIHJldHVybiBmb3IgYSBnaXZlbiBsZXZlbCBvZiByaXNrLCB0aGlzIGlzIGRvbmUgdGhyb3VnaCBkaXZlcnNpZmljYXRpb24uDQoNCg0KVGhyb3VnaCBSIHBhY2thZ2VzIHN1Y2ggYXMgKipxdWFudG1vZCoqLCAqKlBvcnRmb2xpb0FuYWx5dGljcyoqLCBhbmQgKipQZXJmb3JtYW5jZUFuYWx5dGljcyoqLCBTdG9ja3MsIEJvdW5kcyBhbmQgaW5kZXggZGF0YSBjYW4gYmUgcHVsbGVkIGZyb20gdGhlIGludGVybmV0LiBUaGVuLCBpdCBjYW4gYmUgYW5hbHl6ZWQgYW5kIHVzZWQgdG8gY29uc3RydWN0IGEgY3VzdG9tIHBvcnRmb2xpbyB0aGF0IGlzIHRhaWxvcmVkIHRvIHNwZWNpZmljIGNvc3QgYW5kIG9iamVjdGl2ZXMuIFBvcnRmb2xpbyBzdWNoIGFzICBFZmZpY2llbnQgRnJvbnRpZXIsIHdoaWNoIG1lYXN1cmVzIGV4cGVjdGVkIHJldHVybiB2ZXJzdXMgUmlzayBjYW4gdGhlbiBiZSBjb25zdHJ1Y3RlZC4NCg0KDQojIFBhY2thZ2VzIHVzZWQNCg0KYGBge3Igc2V0dXAsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPUZ9DQpyZXF1aXJlKFBvcnRmb2xpb0FuYWx5dGljcykNCnJlcXVpcmUoUGVyZm9ybWFuY2VBbmFseXRpY3MpDQoNCnJlcXVpcmUocXVhbnRtb2QpDQpyZXF1aXJlKHpvbykNCnJlcXVpcmUocGxvdGx5KQ0KcmVxdWlyZShkYXRhLnRhYmxlKQ0KDQojIyBmb3Igb3B0aW1pc2F0aW9uDQojIGxpYnJhcnkoREVvcHRpbSkNCiMgbGlicmFyeShST0kpDQojIHJlcXVpcmUoUk9JLnBsdWdpbi5xdWFkcHJvZykNCiMgcmVxdWlyZShST0kucGx1Z2luLmdscGspDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChyZXN1bHRzID0gJ2hvbGQnLCBlY2hvID0gVCkNCmBgYA0KDQojIERhdGEgSW5wdXQNCg0KU2VsZWN0aW5nIHRoZSA1IGJpZ2dlc3QgdGVjaG5vbG9neSBzdG9ja3MgYW5kIEdTUEMoUyZQNTAwKSwgSFNJKEhLIGluZGV4KSBhbmQgU1RJKFNHIEluZGV4KSBhcyBpbnB1dHMuDQoNCmBgYHtyICwgbWVzc2FnZT1GQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBHZXQgZmluYW5jaWFsIGRhdGEoYWRqdXN0ZWQgcmV0dXJucyBhcmUgd2hhdCB3ZSBhcmUgYWZ0ZXIpIHdpdGggcXVhbnRtb2Qgd2l0aCB5YWhvbw0KIyBBbHRlcm5hdGl2ZWx5LCBxdWFudG1vZCBhcHBlYXJzIHRvIHBsYXkgd2VsbCB3aXRoIHF1YW5kYSBhbmQgZ29vZ2xlIGFzIHdlbGwNCg0KIyBmb3IgdGhlIDUgaG9yc2VtZW4gb2YgdGhlIHRlY2hwb2NhbHlzZSArIFMmUCBpbmRleA0KZ2V0U3ltYm9scyhjKCJNU0ZUIiwgIkdPT0dMIiwgIkFBUEwiLCAgIkFNWk4iLCAiRkIiLCAiXkdTUEMiLCAiXkhTSSIsICJeU1RJIiksIHNyYz0ieWFob28iLCBhdXRvLmFzc2lnbj1UUlVFKQ0KICMgZnJvbT0iMjAwNy0wMS0wMSIgICMgYnkgZGVmYXVsdA0KDQojIEFzc2lnbiB0byBkYXRhZnJhbWUNCiMgZm9yIGRhdGEgZnJvbSB5YWhvbyB0aGUgYWRqdXN0ZWQgY2xvc2UgcHJpY2UgaXMgYXQgdGhlIDZ0aCBjb2x1bW4NCnByaWNlcy5kYXRhIDwtIG1lcmdlLnpvbyhNU0ZUWyw2XSwgR09PR0xbLDZdLCBBQVBMWyw2XSwgQU1aTlssNl0sIEZCWyw2XSwgR1NQQ1ssNl0sIEhTSVssNl0sIFNUSVssNl0pDQojIG5vdGUgdGhhdCBmb3IgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiBxdWFudG1vZCwgdGhlIGFkanVzdGVkIGNsb3NlIGNvbHVtbiBhcHBlYXJzIHRvIG5vIGxvbmdlciBpbmNsdWRlIGRpdmlkZW5kIGFkanVzdG1lbnRzDQoNCiMgQ2FsY3VsYXRlIHJldHVybnMNCnJldHVybnMuZGF0YSA8LSBDYWxjdWxhdGVSZXR1cm5zKHByaWNlcy5kYXRhKSAjIHRoaXMgdXNlIHRoZSBiYXNpYyBsYWcgZnVuY3Rpb24sIHdoaWNoIHdpbGwgcnVuIGludG8gaXNzdWUgd2l0aCB0aWR5IHZlcnNlDQojIG5vdGUgdGhlcmUgaXMgdHdvIGNvbW1vbmx5IHR3byB3YXlzIHRvIGNhbGN1bGF0ZSByZXR1cm5zLCBvbmUgaXMgYXJpdGhtZXRpYyBhbmQgdGhlIG90aGVyIGlzIGxvZ2FyaXRobWljDQojIGJ5IGRlZmF1bHQsIENhbGN1bGF0ZVJldHVybnMoKSBmdW5jdGlvbiB1c2UgYXJpdGhtZXRpYw0KcmV0dXJucy5kYXRhIDwtIG5hLm9taXQocmV0dXJucy5kYXRhKQ0KDQojIFNldCBuYW1lcw0KY29sbmFtZXMocmV0dXJucy5kYXRhKSA8LSBjKCJNU0ZUIiwgIkdPT0dMIiwgIkFBUEwiLCAiQU1aTiIsICJGQiIsICJeR1NQQyIsICJeSFNJIiwgIl5TVEkiKQ0KDQpgYGANCg0KIyMgUmV0dXJuIGFuZCBSaXNrIGV4cGxhbmF0aW9uDQp0d28gY29tbW9uIG1ldGhvZHMgdG8gY2FsY3VsYXRlIHJldHVybg0KDQoqIEFyaXRobWV0aWMgV2F5DQoNCiRyX3QgPSAgXGZyYWN7UF90LVBfe3QtMX19e1Bfe3QtMX19ID0gXGZyYWN7UF90fXtQX3t0LTF9fS0xJA0KDQoqIGxvZ2FyaXRobWljIHdheQ0KDQokcl90ID0gXGxvZ3tcZnJhY3tQX3R9e1Bfe3QtMX19fSA9IFxsb2d7UH0tIFxsb2d7UF97dC0xfX0kDQoNCldoaWxlIHRoZXJlIGFyZSB2YXJpb3VzIG1ldGhvZHMgdG8gY2hhcmFjdGVyaXplIHJpc2ssIHRoZSBtb3N0IHBvcHVsYXIgcGFyYW1ldGVyIGlzIHRoZSBTdGFuZGFyZCBkZXZpYXRpb24sIHRoYXQgd2hpY2ggd2lsbCBiZSBleHBsb3JlZCBpbiB0aGUgZm9sbG93aW5nIHNlY3Rpb25zLCBpdCBpcyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHJpc2sgY2FuIGJlIG1lYXN1cmVkIGluIG90aGVyIG1ldGhvZHMgdG9vLiBTdWNoIGFzIA0KDQpGcm9tIFtJbnZlc3RvcGVkaWFdKGh0dHBzOi8vd3d3LmludmVzdG9wZWRpYS5jb20vd2Fsa3Rocm91Z2gvZnVuZC1ndWlkZS91aXQtaGVkZ2UtZnVuZC1yZWl0L2hmL3N0YW5kYXJkLWRldmlhdGlvbi12YWx1ZS1hdC1yaXNrLmFzcHgjaXh6ejR6eWVTYzdQSikgDQoNCiogU3RhbmRhcmQgRGV2aWF0aW9uKFN0ZERldikNCg0KVGhlIG1vc3QgY29tbW9uIHJpc2sgbWVhc3VyZSB1c2VkIGluIGJvdGggaGVkZ2UgZnVuZCBhbmQgbXV0dWFsIGZ1bmQgZXZhbHVhdGlvbnMgaXMgdGhlIHN0YW5kYXJkIGRldmlhdGlvbi4gVGhlIHN0YW5kYXJkIGRldmlhdGlvbiwgaW4gdGhpcyBjYXNlLCBpcyB0aGUgbGV2ZWwgb2Ygdm9sYXRpbGl0eSBvZiByZXR1cm5zIG1lYXN1cmVkIGluIHBlcmNlbnRhZ2UgdGVybXMsIGFuZCB1c3VhbGx5IHByb3ZpZGVkIG9uIGFuIGFubnVhbCBiYXNpcy4gU3RhbmRhcmQgZGV2aWF0aW9uIGdpdmVzIGEgZ29vZCBpbmRpY2F0aW9uIG9mIHRoZSB2YXJpYWJpbGl0eSBvZiBhbm51YWwgcmV0dXJucyBhbmQgbWFrZXMgaXQgZWFzeSB0byBjb21wYXJlIHRvIG90aGVyIGZ1bmRzIHdoZW4gY29tYmluZWQgd2l0aCBhbm51YWwgcmV0dXJuIGRhdGENCg0KKiBWYWx1ZSBBdCBSaXNrKFZBUikNCg0KVmFSIG1lYXN1cmVzIHRoZSBkb2xsYXItbG9zcyBleHBlY3RhdGlvbiB0aGF0IGNhbiBvY2N1ciB3aXRoIGEgNSUgcHJvYmFiaWxpdHkuIEl0IGFkZHMgYW5vdGhlciBkaW1lbnNpb24gYmVjYXVzZSBpdCBtYWtlcyBpdCBwb3NzaWJsZSB0byBjb21wYXJlIHR3byBmdW5kcyB3aXRoIGRpZmZlcmVudCBhdmVyYWdlIHJldHVybnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbi4gVmFSIHdvdWxkIGluZGljYXRlIHRoZSBkb2xsYXIgYW1vdW50IG9mIGxvc3MgdGhhdCBpcyBwb3NzaWJsZSB3aXRoIGVhY2ggZnVuZCB3aXRoIGEgNSUgcHJvYmFiaWxpdHkuDQoNClB1dCBhbm90aGVyIHdheSwgVmFSIHdvdWxkIHRlbGwgeW91IHdpdGggOTUlIGNvbmZpZGVuY2UgdGhhdCB5b3VyIGxvc3NlcyB3b3VsZCBub3QgZXhjZWVkIGEgY2VydGFpbiBwb2ludC4gKFlvdSBjYW4gbmV2ZXIgYmUgMTAwJSBjb25maWRlbnQgdGhhdCB5b3Ugd29uJ3QgbG9zZSBhbiBlbnRpcmUgaW52ZXN0bWVudC4pIEl0IHRyaWVzIHRvIGFuc3dlciB0aGUgcXVlc3Rpb24gIkdpdmVuIGFuIGludmVzdG1lbnQgb2YgYSBwYXJ0aWN1bGFyIHJldHVybiBhbmQgdm9sYXRpbGl0eSwgd2hhdCdzIHRoZSB3b3JzdCB0aGF0IGNvdWxkIGhhcHBlbj8iDQoNCiogW0V4cGVjdGVkIFNob3J0ZmFsbChFUyldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0V4cGVjdGVkX3Nob3J0ZmFsbCkNCg0KRXhwZWN0ZWQgU2hvcnRmYWxsIChFUykgaXMgYSByaXNrIG1lYXN1cmUtYSBjb25jZXB0IHVzZWQgaW4gdGhlIGZpZWxkIG9mIGZpbmFuY2lhbCByaXNrIG1lYXN1cmVtZW50IHRvIGV2YWx1YXRlIHRoZSBtYXJrZXQgcmlzayBvciBjcmVkaXQgcmlzayBvZiBhIHBvcnRmb2xpby4gVGhlICJleHBlY3RlZCBzaG9ydGZhbGwgYXQgcSUgbGV2ZWwiIGlzIHRoZSBleHBlY3RlZCByZXR1cm4gb24gdGhlIHBvcnRmb2xpbyBpbiB0aGUgd29yc3Qge1xkaXNwbGF5c3R5bGUgcX0gcSUgb2YgY2FzZXMuIEVTIGlzIGFuIGFsdGVybmF0aXZlIHRvIHZhbHVlIGF0IHJpc2sgdGhhdCBpcyBtb3JlIHNlbnNpdGl2ZSB0byB0aGUgc2hhcGUgb2YgdGhlIHRhaWwgb2YgdGhlIGxvc3MgZGlzdHJpYnV0aW9uLg0KRXhwZWN0ZWQgc2hvcnRmYWxsIGlzIGFsc28gY2FsbGVkIGNvbmRpdGlvbmFsIHZhbHVlIGF0IHJpc2sgKENWYVIpLCBhdmVyYWdlIHZhbHVlIGF0IHJpc2sgKEFWYVIpLCBhbmQgZXhwZWN0ZWQgdGFpbCBsb3NzIChFVEwpLg0KDQojIERlZmluaW5nIHNvbWUgcG9ydGZvbGlvIHBhcmFtZXRlcnMNCg0KQSBzaW5nbGUgaXRlbSBpcyB0aHVzIHJlc3RyaWN0ZWQgdGFrZSBhIGJldHdlZW4gMC4wNSB0byAwLjQ1IHBvcnRpb24gb2YgdGhlIHBvcnRmb2xpby4gVGhlIHBvcnRmb2xpbyBpcyBzcGVjaWZpZWQgdG8gYmUgYSBmdWxsIGludmVzdG1lbnQuDQoNCg0KYGBge3J9DQojIGluaXRpYWwgcG9ydGZvbGlvIG9iamVjdA0KaW5pdCA8LSBwb3J0Zm9saW8uc3BlYyhhc3NldHM9Y29sbmFtZXMocmV0dXJucy5kYXRhKSkNCiMgaW5pdGlhbCBjb25zdHJhaW50cw0KaW5pdCA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89aW5pdCwgdHlwZT0iZnVsbF9pbnZlc3RtZW50IikNCiMgaW5pdCA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89aW5pdCwgdHlwZT0ibG9uZ19vbmx5IikNCmluaXQgPC0gYWRkLmNvbnN0cmFpbnQocG9ydGZvbGlvPWluaXQsIHR5cGU9ImJveCIsIG1pbj0wLjA1LCBtYXg9MC40NSkNCiMgaW5pdCA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89aW5pdCwgdHlwZT0iZ3JvdXAiLA0KIyAgICAgICAgICAgICAgICAgICAgICAgIGdyb3Vwcz1saXN0KGMoMSwgMyksDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygyLCA0LCA1KSksDQojICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfbWluPTAuMDUsDQojICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfbWF4PTAuNykNCmBgYA0KDQojT3B0aW1pemF0aW9uIGFuZCBDYWxjdWxhdGlvbg0KDQojIyBPcHRpbWl6ZSB0aGUgcG9ydGZvbGlvIHVzaW5nIHJhbmRvbQ0KDQpgYGB7ciwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KIyMgQSBtb3JlIENvbnZlbnRpb25hbCBhcHByb2FjaCBpcyB0cmVhdGluZyByaXNrIGFzIFN0ZERldg0KIyMgQ3JlYXRlcyBhIG5ldyBwb3J0Zm9saW8gb2JqZWN0IHVzaW5nIHBvcnRmIGFuZCBhZGRzIFN0ZERldiBhcyBhbiBvYmplY3RpdmUNCm1lYW5zdGQucG9ydGYgPC0gYWRkLm9iamVjdGl2ZShwb3J0Zm9saW89aW5pdCwgdHlwZT0icmlzayIsIG5hbWU9IlN0ZERldiIpICU+JQ0KICBhZGQub2JqZWN0aXZlKHBvcnRmb2xpbz0uLCB0eXBlPSJyZXR1cm4iLCBuYW1lPSJtZWFuIikNCg0Kb3B0IDwtIG9wdGltaXplLnBvcnRmb2xpbyhyZXR1cm5zLmRhdGEsIG1lYW5zdGQucG9ydGYsIG9wdGltaXplX21ldGhvZD0icmFuZG9tIiwgdHJhY2U9VCwgc2VhcmNoX3NpemUgPSAyMDAwMCkgDQoNCmNoYXJ0LlJpc2tSZXdhcmQob3B0LCByaXNrLmNvbD0iU3RkRGV2IiwgcmV0dXJuLmNvbD0ibWVhbiIsICBjaGFydC5hc3NldHMgPSBGKQ0KDQpgYGANCg0KDQogDQpgYGB7ciwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGfQ0KbWVhbnZhci5lZjwtIGNyZWF0ZS5FZmZpY2llbnRGcm9udGllcihSPXJldHVybnMuZGF0YSwgcG9ydGZvbGlvPW1lYW5zdGQucG9ydGYsIHR5cGU9Im1lYW4tdmFyIiwgbi5wb3J0Zm9saW9zID0gNTApDQojIHN1bW1hcnkobWVhblN0ZCwgZGlnaXRzPTIpDQoNCg0KIyBUaGUgUkFSLnRleHQgYXJndW1lbnQgY2FuIGJlIHVzZWQgZm9yIHRoZSByaXNrLWFkanVzdGVkLXJldHVybiBuYW1lIG9uIHRoZSBsZWdlbmQsDQojIGJ5IGRlZmF1bHQgaXQgaXMgJ01vZGlmaWVkIFNoYXJwZSBSYXRpbycNCmNoYXJ0LkVmZmljaWVudEZyb250aWVyKG1lYW52YXIuZWYsIG1hdGNoLmNvbD0iU3RkRGV2IiwgdHlwZT0ibCIsIFJBUi50ZXh0PSJTaGFycGUgUmF0aW8iLCBwY2g9NCwgcmYgPSAwLjAxLzEyKQ0KDQpgYGANCg0KIyMjIFNoYXJwZSBSYXRpbw0KDQoiVGhlIFNoYXJwZSByYXRpbyBjaGFyYWN0ZXJpemVzIGhvdyB3ZWxsIHRoZSByZXR1cm4gb2YgYW4gYXNzZXQgY29tcGVuc2F0ZXMgdGhlIGludmVzdG9yIGZvciB0aGUgcmlzayB0YWtlbiIuICBUaGUgaGlnaGVyIFNoYXJwZSBSYXRpbyBtZWFucyB0aGUgYmV0dGVyIGludmVzdG1lbnQgb3B0aW9uLiBJbiBhIHNldCBvZiByaXNreSBhc3NldHMsIHdlIGNhbiBmaW5kIHRoZSBvcHRpbWFsIHBvcnRmb2xpbyBhc3NldCBhbGxvY2F0aW9ucyBzbyB0aGF0IHRoZSBTaGFycGUgUmF0aW9uIGlzIHRoZSBsYXJnZXN0Lg0KDQpJbiBhbm90aGVyIHdvcmQsIFRoZSBTaGFycGUgcmF0aW8gaXMgc2ltcGx5IHRoZSByZXR1cm4gcGVyIHVuaXQgb2YgcmlzayAocmVwcmVzZW50ZWQgYnkgdmFyaWFiaWxpdHkpLg0KDQojIyMgW0NhcGl0YWwgTWFya2V0IExpbmUgLSBDTUxdKGh0dHBzOi8vd3d3LmludmVzdG9wZWRpYS5jb20vdGVybXMvYy9jbWwuYXNwI2l4eno1MEhyZFA5eEEpDQoNClRoZSBjYXBpdGFsIG1hcmtldCBsaW5lIChDTUwpIGFwcGVhcnMgaW4gdGhlIGNhcGl0YWwgYXNzZXQgcHJpY2luZyBtb2RlbCB0byBkZXBpY3QgdGhlIHJhdGVzIG9mIHJldHVybiBmb3IgZWZmaWNpZW50IHBvcnRmb2xpb3Mgc3ViamVjdCB0byB0aGUgcmlzayBsZXZlbCAoc3RhbmRhcmQgZGV2aWF0aW9uKSBmb3IgYSBtYXJrZXQgcG9ydGZvbGlvIGFuZCB0aGUgcmlzay1mcmVlIHJhdGUgb2YgcmV0dXJuLg0KDQpUaGUgY2FwaXRhbCBtYXJrZXQgbGluZSBpcyBjcmVhdGVkIGJ5IHNrZXRjaGluZyBhIHRhbmdlbnQgbGluZSBmcm9tIHRoZSBpbnRlcmNlcHQgcG9pbnQgb24gdGhlIGVmZmljaWVudCBmcm9udGllciB0byB0aGUgcGxhY2Ugd2hlcmUgdGhlIGV4cGVjdGVkIHJldHVybiBvbiBhIGhvbGRpbmcgZXF1YWxzIHRoZSByaXNrLWZyZWUgcmF0ZSBvZiByZXR1cm4uIEhvd2V2ZXIsIHRoZSBDTUwgaXMgYmV0dGVyIHRoYW4gdGhlIGVmZmljaWVudCBmcm9udGllciBiZWNhdXNlIGl0IGNvbnNpZGVycyB0aGUgaW5mdXNpb24gb2YgYSByaXNrLWZyZWUgYXNzZXQgaW4gdGhlIG1hcmtldCBwb3J0Zm9saW8uDQoNCg0KYGBge3IsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRiwgcmVzdWx0cyA9ICdoaWRlJ30NCiMgZXh0cmFjdGluZyByZXN1dGxzIGZyb20gdGhlIGNsYXNzICJmcm9udGllciIsIGV4dHJhY3RTdGF0cygpIGRvZXNuJ3Qgd29yayBmb3IgZnJvbnRpZXIgY2xhc3MNCm1lYW52YXIuZWYuYWxsb2NhdGlvbjwtYXMuZGF0YS5mcmFtZShzdW1tYXJ5KG1lYW52YXIuZWYpW1sxXV0pDQptZWFudmFyLmVmLm91dHB1dDwtYXMuZGF0YS5mcmFtZShzdW1tYXJ5KG1lYW52YXIuZWYpW1syXV0pDQoNCiMgc2V0dGluZyB0aGUgcm93IG5hbWUgYXMgaWQgZm9yIHRoZSBvdXRwdXQNCm1lYW52YXIuZWYub3V0cHV0JGlkIDwtYXMuaW50ZWdlcihyb3cubmFtZXMobWVhbnZhci5lZi5vdXRwdXQpKQ0KbWVhbnZhci5lZi5hbGxvY2F0aW9uJGlkIDwtYXMuaW50ZWdlcihyb3cubmFtZXMobWVhbnZhci5lZi5hbGxvY2F0aW9uKSkNCg0KI2NhbGN1bGF0ZSB0aGUgU2hhcGVSYXRpbyBmb3IgdGhlIEVGIG91dHVwdXQNCnNldERUKG1lYW52YXIuZWYub3V0cHV0KVssIFNoYXJwZVJhdGlvOj0gbWVhbiAvIFN0ZERldl0NCg0KDQojIyBjb250cnVjdGluZyBDTUwgbGluZQ0KTWF4U2hhcnBlPC1tZWFudmFyLmVmLm91dHB1dFtTaGFycGVSYXRpbz09bWF4KFNoYXJwZVJhdGlvKV0NCnJpc2tfZnJlZV9yYXRlPSAwLjAxLzEyICMgYm91bmQvIEZEDQoNCnJhdGlvPC1zZXEoMCwxLDAuMSkNCg0KQ01MPC0gZGF0YS50YWJsZSgNCkNNTF9yZXR1cm49TWF4U2hhcnBlJG1lYW4qcmF0aW8gKyByaXNrX2ZyZWVfcmF0ZSooMS1yYXRpbyksDQpDTUxfcmlzayA9IE1heFNoYXJwZSRTdGREZXYqcmF0aW8NCikNCmBgYA0KDQoNCiMgUGxvdHRpbmcgdGhlIHJlc3VsdHMgd2l0aCBwbG90bHkNCg0KTm90ZSB0aGF0IHRoZSBtZWFuIHJldHVybnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBkZXBpY3RlZCBoZXJlIGFyZSBtb250aGx5IGZpZ3VyZXMNCg0KdGhpcyBwbG90IHNldHVwIGlzIGluc3BpcmVkIGJ5IGh0dHBzOi8vbW9kZXJuZGF0YS5wbG90Lmx5L3BvcnRmb2xpby1vcHRpbWl6YXRpb24tdXNpbmctci1hbmQtcGxvdGx5Ly4NCg0KYGBge3IgcGxvdGx5MSwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gOH0NCg0KZXggPC0gZGF0YS5mcmFtZShleHRyYWN0U3RhdHMob3B0KSkNCiMgZGF0YS5mcmFtZShleHRyYWN0U3RhdHMobWVhbnZhci5lZikpDQoNCnBsb3RfbHkoZGF0YSA9bWVhbnZhci5lZi5vdXRwdXQsIHggPSB+U3RkRGV2LCB5ID0gfm1lYW4sIGNvbG9yID0gflNoYXJwZVJhdGlvLCBtb2RlID0gIm1hcmtlcnMiLCBzaG93bGVnZW5kID0gRiwgDQogICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgIGluaGVyaXQgPSBGKSAlPiUgDQogIA0KICBhZGRfdHJhY2UoZGF0YSA9IGV4LCB4ID0gflN0ZERldiwgeSA9IH5tZWFuLCBtb2RlID0gIm1hcmtlcnMiLCBzaG93bGVnZW5kID0gRiwgbWFya2VyID0gbGlzdChjb2xvciA9ICIjRjdDODczIiwgc2l6ZSA9IDUpLA0KICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIpICU+JSANCiAgDQogIGFkZF9saW5lcyhkYXRhID0gQ01MLCB4PSB+Q01MX3Jpc2ssIHkgPSB+Q01MX3JldHVybiklPiUNCiAgDQogIGxheW91dCh0aXRsZSA9ICJSYW5kb20gUG9ydGZvbGlvcyB3aXRoIFBsb3RseSIsDQogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTWVhbiBSZXR1cm5zIiwgdGlja2Zvcm1hdCA9ICIuMiUiKSwNCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJTdGFuZGFyZCBEZXZpYXRpb24iLCB0aWNrZm9ybWF0ID0gIi4yJSIpLA0KICAgICAgICAgcGFwZXJfYmdjb2xvciA9ICdyZ2IoMjQ4LCAyNDgsIDI1NSknLA0KICAgICAgICAgcGxvdF9iZ2NvbG9yID0gJ3JnYigyNDgsIDI0OCwgMjU1KScsDQogICAgICAgICBsZWdlbmQgPSBsaXN0KHggPSAwLjAyOSwgeSA9IDEuMDM4LA0KICAgICAgICAgICAgICAgICAgICAgICBmb250ID0gbGlzdChzaXplID0gMTApKSkNCg0KYGBgDQoNCiMgQWxsb2NhdGlvbiBvZiBpbnZlc3RtZW50IGFtb25nIHRoZSBFZmZpY2llbnQgRnJvbnRpZXINCg0KVGhlIHBvcnRmb2xpbyBhY3Jvc3MgdGhlICpFZmZpY2llbnQgRnJvbnRpZXIqIGNhbiBiZSB2aXN1YWxsaXNlZCBhcyBmb2xsb3csIGFsb25nIHdpdGggdGhlICoqU2hhcnBlIFJhdGlvKiogb2YgdGhhdCBwYXJ0aWN1bGFyIHNldHVwIGZvciBwb3J0Zm9saW8uDQoNCmBgYHtyIHBsb3RseTIsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDh9DQoNCm1lYW52YXIuZWYuYWxsb2NhdGlvbi5tZWx0IDwtIHJlc2hhcGUyOjptZWx0KG1lYW52YXIuZWYuYWxsb2NhdGlvbiwgaWQudmFycz1jKCJpZCIpKQ0KIA0KcGxvdF9seShtZWFudmFyLmVmLmFsbG9jYXRpb24ubWVsdCwgeCA9IH5pZCwgeSA9IH52YWx1ZSwgIGNvbG9yID0gfnZhcmlhYmxlLCB0eXBlID0gImJhciIpICU+JQ0KICANCiAgYWRkX3RyYWNlKGRhdGEgPSBtZWFudmFyLmVmLm91dHB1dCwgeCA9IH5pZCwgeSA9IH5TaGFycGVSYXRpbywgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycsIG5hbWUgPSAnU2hhcnBlUmF0aW8nLA0KICAgICAgICAgICAgeWF4aXMgPSAneTInLA0KICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAnIzQ1MTcxRCcpLA0KICAgICAgICAgICAgaG92ZXJpbmZvID0gInRleHQiLA0KICAgICAgICAgICAgdGV4dCA9IH5wYXN0ZShTaGFycGVSYXRpbyksIGluaGVyaXQgPSBGKSAlPiUNCiAgDQogIGxheW91dCh0aXRsZSA9ICJQb3J0Zm9saW8gd2VpZ2h0cyBhY3Jvc3MgZnJvbnRpZXIiLCBiYXJtb2RlID0gInN0YWNrIiwNCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJJbmRleCIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIldlaWdodHMoJSkiLCB0aWNrZm9ybWF0ID0gIi4wJSIpLA0KICAgICAgICAgeWF4aXMyID0gbGlzdChzaWRlID0gJ3JpZ2h0Jywgb3ZlcmxheWluZyA9ICJ5IiwgdGl0bGUgPSAnU2hhcnBlUmF0aW8nLCBzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFKSwNCiAgICAgICAgIGxlZ2VuZCA9IGxpc3QoeCA9IDAuMDI5LCB5ID0gMS4wMzgsDQogICAgICAgICAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KHNpemUgPSAxMCkpLA0KICAgICAgICAgbWFyZ2luID0gbGlzdChsID0gMTAwLCByID0gNTAsIHQgPSA3MCwgYiA9IDcwKSwNCiAgICAgICAgIHBhcGVyX2JnY29sb3IgPSAncmdiKDI0OCwgMjQ4LCAyNTUpJywNCiAgICAgICAgIHBsb3RfYmdjb2xvciA9ICdyZ2IoMjQ4LCAyNDgsIDI1NSknKQ0KDQoNCmBgYA0KDQojIyBDdXN0b20gY29zdCBhbmQgcmV0dXJuIGZvciBwb3J0Zm9saW8gb3B0aW1pemF0aW9uDQoNCkJlbG93IHNob3cgdGhlIG9wdGltaXphdGlvbiBvZiB0aGUgcG9ydGZvbGlvIHVzaW5nIGEgY3VzdG9tIGZ1bmN0aW9uLCBpbiB0aGlzIGNhc2UsIHRoZSBhbm51YWwgbWVhbiBhbmQgc3RkLiANCnRoaXMgaXMgYWRhcHRlZCBhbmQgc2xpZ2h0bHkgbW9kaWZpZWQgZnJvbSBodHRwczovL3N0YXQuZXRoei5jaC9waXBlcm1haWwvci1zaWctZmluYW5jZS8yMDE2cTEvMDEzODE3Lmh0bWwNCg0KYGBge3J9DQoNCiMgRGVmaW5lIG1lYW4gUEEgZnVuY3Rpb24NCkFubnVhbG1lYW4gPC0gZnVuY3Rpb24oUiwgd2VpZ2h0cywgbj02MCwgZ2VvbWV0cmljPUZBTFNFKXsNCmFzLnZlY3RvcihzdW0oUmV0dXJuLmFubnVhbGl6ZWQoeHRzOjpsYXN0KFIsbiksIGdlb21ldHJpYz1nZW9tZXRyaWMpKndlaWdodHMpKQ0KfQ0KDQojIERlZmluZSBzdGQgYW5udWFsbHkgZnVuY3Rpb24NCkFubnVhbHNkIDwtIGZ1bmN0aW9uKFIsIHdlaWdodHM9TlVMTCl7DQphcy5udW1lcmljKFN0ZERldihSPVIsIHdlaWdodHM9d2VpZ2h0cykqc3FydCgxMikpICMgaGFyZGNvZGVkIGZvciBtb250aGx5IGRhdGENCn0NCg0KI2FubnVhbGl6ZWQgcmV0dXJuDQptZWFuc3RkLnBvcnRmIDwtIGFkZC5vYmplY3RpdmUocG9ydGZvbGlvPW1lYW5zdGQucG9ydGYsDQp0eXBlPSJyZXR1cm4iLCAjIHRoZSBraW5kIG9mIG9iamVjdGl2ZSB0aGlzIGlzDQpuYW1lPSJBbm51YWxtZWFuIiwgIyBuYW1lIG9mIHRoZSBmdW5jdGlvbg0KbXVsdGlwbGllcj0xICMgdXNlIGl0IGluIHRoZSBvYmplY3RpdmUNCikNCg0KI2FubnVhbGl6ZWQgc3RhbmRhcmQgZGV2aWF0aW9uDQptZWFuc3RkLnBvcnRmIDwtIGFkZC5vYmplY3RpdmUocG9ydGZvbGlvPW1lYW5zdGQucG9ydGYsDQp0eXBlPSJyaXNrIiwgIyB0aGUga2luZCBvZiBvYmplY3RpdmUgdGhpcyBpcw0KbmFtZT0iQW5udWFsc2QiLCAjIHRvIG1pbmltaXplIGZyb20gdGhlIHNhbXBsZQ0KbXVsdGlwbGllcj0xICMgIHVzZSBpdCBpbiB0aGUgb2JqZWN0aXZlDQopDQoNCg0KICMgbWFrZSBzdXJlIHRvIHJ1biB3aXRoIHRyYWNlPVRSVUUgZm9yIHRoZSBleHRyYWN0IHN0YXRzIG91dHB1dA0Kb3B0IDwtIG9wdGltaXplLnBvcnRmb2xpbyhyZXR1cm5zLmRhdGEsIG1lYW5zdGQucG9ydGYsIG9wdGltaXplX21ldGhvZD0icmFuZG9tIiwgdHJhY2U9VFJVRSkgDQpjaGFydC5SaXNrUmV3YXJkKG9wdCwgcmlzay5jb2w9IkFubnVhbHNkLkFubnVhbHNkIiwgcmV0dXJuLmNvbD0iQW5udWFsbWVhbi5Bbm51YWxtZWFuIikNCg0KYGBgDQoNCg==